package com.gc.server.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.gc.server.dao.PlanDao;
import com.gc.server.dao.UserDao;
import com.gc.server.entity.*;
import com.gc.server.enums.TodoStatusEnum;
import com.gc.server.enums.TodoTypeEnum;
import com.gc.server.service.GoodsRecordService;
import com.gc.server.service.GoodsService;
import com.gc.server.service.UserService;
import com.gc.server.vo.*;
import com.gc.server.vo.down.ShopDown;
import com.gc.server.vo.down.TodoDown;
import com.yf.response.RRException;
import com.yf.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

import com.gc.server.dao.TodoDao;
import com.gc.server.service.TodoService;
import com.yf.service.impl.BaseServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;

/**
 * 日程Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Tue Mar 10 11:17:45 CST 2020
 */
@Service
public class TodoServiceImpl extends BaseServiceImpl<TodoEntity> implements TodoService {

    private TodoDao todoDao;

    @Autowired
    private GoodsRecordService recordService;


    @Autowired
    public void setDao(TodoDao todoDao) {
        this.todoDao = todoDao;
        super.setBaseDao(todoDao);
    }


    @Override
    public List<TodoVo> queryListVo(TodoVo todoVo) {
        return todoDao.queryListVo(todoVo);
    }

    @Override
    public TodoVo getVo(Long id) {
        return todoDao.getVo(id);
    }


    /**内部方法**/


    /**
     * 外部方法实现
     **/


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(Long planId, Date date, Integer type, Long userId, String[] titles) {
        // 首先删除所有未完成的
        todoDao.del(userId, date, type, TodoStatusEnum.TODO.getIndex());
        if (titles == null) return;
        Set<String> titleSet = new HashSet<>(Arrays.asList(titles));
        for (String title : titleSet) {
            TodoEntity todoEntity = todoDao.findByUserIdAndTitleAndTypeAndDate(userId, title, type, date);
            if (todoEntity == null) {
                todoEntity = new TodoEntity(planId, date, type, title, TodoStatusEnum.TODO.getIndex(), userId);
                todoDao.save(todoEntity);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(Long userId, Long id) {
        TodoEntity todoEntity = todoDao.get(id);
        if (todoEntity == null) {
            throw new RRException("日程不存在!");
        }
        if (!todoEntity.getUserId().equals(userId)) {
            throw new RRException("没有权限操作!");
        }
        if (!todoEntity.getStatus().equals(TodoStatusEnum.TODO.getIndex())) {
            throw new RRException("日程完成,无法删除");
        }
        todoEntity.setStatus(TodoStatusEnum.DEL.getIndex());
        todoDao.update(todoEntity);
    }

    @Override
    public void del(Long userId, Date date, Integer type) {
        todoDao.del(userId, date, type, TodoStatusEnum.TODO.getIndex());
    }

    /**
     * 只能操作两种状态
     *
     * @param status
     */
    private void validate(Integer status) {
        if (!status.equals(TodoStatusEnum.TODO.getIndex()) && !status.equals(TodoStatusEnum.WAIT.getIndex())) {
            throw new RRException("数据有误!");
        }
    }

    /**
     * 验证时间
     * @param todoEntity
     */
    private void validateDate(TodoEntity todoEntity){
        if(DateUtil.isSameDay(todoEntity.getDate(),new Date())){
            throw new RRException("只能当天完成!");
        }
    }

    /**
     * 验证状态
     *
     * @param todoEntity
     */
    private void validate(TodoEntity todoEntity, Long userId) {
        if(!DateUtil.isSameDay(todoEntity.getDate(),new Date())){
            throw new RRException("只能当天完成");
        }
        if (todoEntity.getStatus() != null && !todoEntity.getStatus().equals(TodoStatusEnum.TODO.getIndex())) {
            throw new RRException("没有操作权限!");
        }
        if (todoEntity == null) {
            throw new RRException("日程不存在!");
        }
        if (!todoEntity.getUserId().equals(userId)) {
            throw new RRException("没有操作权限!");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TodoEntity completeVisit(TodoEntity tem, Long userId, Long[] ids, Integer[] nums) {
        TodoEntity todoEntity = todoDao.get(tem.getId());
        validate(todoEntity, userId);
        todoEntity.setStatus(tem.getStatus());
        //如果提交的话 设置提交时间
        if (!todoEntity.getStatus().equals(TodoStatusEnum.TODO.getIndex())) {
            todoEntity.setDoneTime(new Date());
        }
        // 地址只有首次可以改
        if (todoEntity.getAddress() == null) {
            todoEntity.setAddress(tem.getAddress());
            todoEntity.setAddressTime(tem.getAddressTime());
        }
        todoEntity.setPriceImg(tem.getPriceImg());
        todoEntity.setPriceTime(tem.getPriceTime());
        todoEntity.setDisplayImg(tem.getDisplayImg());
        todoEntity.setDisplayTime(tem.getDisplayTime());
        todoEntity.setAirImg(tem.getAirImg());
        todoEntity.setAirTime(tem.getAirTime());
        todoEntity.setGroupImg(tem.getGroupImg());
        todoEntity.setGroupTime(tem.getGroupTime());
        todoEntity.setChat(tem.getChat());
        todoEntity.setSummary(tem.getSummary());
        todoEntity.setUserId(userId);
        todoDao.update(todoEntity);
        // 存储物料记录
        if (ids != null) {
            recordService.record(userId, todoEntity.getId(), ids, nums);
        }
        return todoEntity;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public TodoEntity completeSend(TodoEntity tem, Long userId) {
        TodoEntity todoEntity = todoDao.get(tem.getId());
        validate(todoEntity, userId);
        todoEntity.setStatus(tem.getStatus());
        //如果提交的话 设置提交时间
        if (!todoEntity.getStatus().equals(TodoStatusEnum.TODO.getIndex())) {
            todoEntity.setDoneTime(new Date());
        }
        // 地址只有首次可以改
        if (todoEntity.getAddress() == null) {
            todoEntity.setAddress(tem.getAddress());
            todoEntity.setAddressTime(tem.getAddressTime());
        }
        todoEntity.setSendNum(tem.getSendNum());
        todoEntity.setSendImg(tem.getSendImg());
        todoEntity.setSendTime(tem.getSendTime());
        todoEntity.setSummary(tem.getSummary());
        todoEntity.setAudio(tem.getAudio());
        todoDao.update(todoEntity);
        updatePlanDone(todoEntity.getId());
        return todoEntity;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public TodoEntity completeAct(TodoEntity tem, Long userId, Long[] ids, Integer[] nums) {
        TodoEntity todoEntity = todoDao.get(tem.getId());
        validate(todoEntity, userId);
        //直接设置确认
        todoEntity.setStatus(TodoStatusEnum.PRE.getIndex());
        //如果提交的话 设置提交时间
//        if(todoEntity.getStatus().equals(TodoStatusEnum.WAIT.getIndex())){
        todoEntity.setDoneTime(new Date());
//        }
        todoEntity.setSummary(tem.getSummary());
        todoEntity.setSellNum(tem.getSellNum());
        todoEntity.setSellImg(tem.getSellImg());
        todoEntity.setSendTime(tem.getSendTime());
//        todoEntity.setUserNum(userNum); 统计当天新增的用户
        todoDao.update(todoEntity);
        // 存储物料记录
        if (ids != null) {
            recordService.record(userId, todoEntity.getId(), ids, nums);
        }
        updatePlanDone(todoEntity.getId());
        return todoEntity;
    }

    @Override
    public List<TodoEntity> findByPlanId(Long planId) {
        return todoDao.findByPlanId(planId);
    }

    @Override
    public List<TodoEntity> findByDateAndUserId(Long userId, Date startDate, Date endDate) {
        return todoDao.findByDateAndUserId(userId, startDate, endDate);
    }

    @Override
    public List<TodoEntity> findByDateAndUserIdAndTopUserId(Long userId, Date startDate, Date endDate, Long topUserId) {
        return todoDao.findByDateAndUserIdAndTopUserId(userId, startDate, endDate, topUserId);
    }



    @Override
    public List<ToDoSumVo> sumByDate(Long userId, Date startDate, Date endDate) {
        List<Long> userIds = userService.findTeam(userId);
        List<TodoVo> todoVos = new ArrayList<>();
        if(userIds.size()>0){
            todoVos = todoDao.findByDateAndIds(startDate, endDate, userIds);
        }
        //开始统计
        Map<Long,ToDoSumVo> map = new HashMap();
        for (int i = 0; i < todoVos.size(); i++) {
            ToDoSumVo toDoSumVo;
            UserEntity user = todoVos.get(i).getUser();
            TodoEntity todoEntity = todoVos.get(i).getTodo();
            if(map.containsKey(user.getId())){
                toDoSumVo = map.get(user.getId());
            }else {
                toDoSumVo = new ToDoSumVo();
            }
            //开始汇总
            toDoSumVo.setTotal(toDoSumVo.getTotal()+1);
            toDoSumVo.setUserName(user.getName());
            toDoSumVo.setUserId(user.getId());
            toDoSumVo.setCode(user.getCode());
            toDoSumVo.setLevel(user.getLevelId());
            if(todoEntity.getStatus().equals(TodoStatusEnum.TODO.getIndex())){
                toDoSumVo.setTodo(toDoSumVo.getTodo()+1);
            }else if (todoEntity.getStatus().equals(TodoStatusEnum.WAIT.getIndex())||todoEntity.getStatus().equals(TodoStatusEnum.PRE.getIndex())){
                toDoSumVo.setWait(toDoSumVo.getWait()+1);
            }else if(todoEntity.getStatus().equals(TodoStatusEnum.SCORE.getIndex())){
                toDoSumVo.setScore(toDoSumVo.getScore()+1);
                toDoSumVo.setPoint(toDoSumVo.getPoint().add(todoEntity.getScore()));
            }
            map.put(user.getId(),toDoSumVo);
        }
        //计算平均分  总分/已完成
        map.values().forEach(toDoSumVo -> {
            if(toDoSumVo.getPoint().compareTo(BigDecimal.ZERO)>0&&toDoSumVo.getScore()+toDoSumVo.getWait()>0){
                toDoSumVo.setAvg(toDoSumVo.getPoint().divide(new BigDecimal(toDoSumVo.getScore()+toDoSumVo.getWait()),2,BigDecimal.ROUND_HALF_UP));
            }
        });
        List<ToDoSumVo> res = map.values().stream().collect(Collectors.toList());
//        res.sort((a,b) -> (int) (a.getLevel() - b.getLevel()));
        res.sort(Comparator.comparing(ToDoSumVo::getAvg));
        return res;
    }

    @Override
    public Integer sumCheck(Long userId) {
        return todoDao.sumCheck(userId);
    }


    @Autowired
    private UserService userService;

    @Autowired
    private PlanDao planDao;

    void updatePlanDone(Long todoId){
        TodoEntity todoEntity = todoDao.get(todoId);
        PlanEntity planEntity = planDao.get(todoEntity.getPlanId());
        if(planEntity.getDone()== null){
            planEntity.setDone(0);
        }else {
            planEntity.setDone(planEntity.getDone()+1);
        }
        planDao.update(planEntity);
    }

    @Override
    public void completeHunt(TodoEntity todoEntity, Long userId) {
        todoEntity.setUserId(userId);
        todoEntity.setDate(new Date());
        todoEntity.setType(TodoTypeEnum.HUNT.getIndex());
        todoEntity.setDoneTime(new Date());
        todoEntity.setStatus(TodoStatusEnum.PRE.getIndex());
        PlanEntity planEntity = planDao.findByDate(new Date(), userId);
        if (planEntity == null) {
            throw new RRException("本周计划暂未创建");
        }
        todoEntity.setPlanId(planEntity.getId());
        todoDao.save(todoEntity);
        updatePlanDone(todoEntity.getId());
    }

    @Override
    public void completeOther(TodoEntity tem, Long userId) {
        TodoEntity todoEntity = todoDao.get(tem.getId());
        validate(todoEntity, userId);
        todoEntity.setSummary(tem.getSummary());
        todoEntity.setStatus(TodoStatusEnum.WAIT.getIndex());
        //如果提交的话 设置提交时间
        if (todoEntity.getStatus().equals(TodoStatusEnum.WAIT.getIndex())) {
            todoEntity.setDoneTime(new Date());
        }
        todoDao.update(todoEntity);
        updatePlanDone(todoEntity.getId());
    }

    @Override
    public List<TodoEntity> findMyShopUserUser(Long pid, Long userId, Date date) {
        return todoDao.findMyShopUserUser(pid, userId, date);
    }

    @Override
    public List<TodoVo> findVoByTopUser(Long pid, Date date) {
        return todoDao.findVoByTopUser(pid, date);
    }

//    @Override
//    public void download(TodoVo todoVo, HttpServletResponse response) {
//        List<TodoVo> todoEntities = queryListVo(todoVo);
//        Map<String, BigDecimal> sum = new HashMap<>();
//        List<TodoExcel> todoExcels = new ArrayList<>();
//        List<TodoSumExcel> sumExcels = new ArrayList<>();
//        for (TodoVo vo : todoEntities) {
//            if(vo.getUser()==null)continue;
//            TodoExcel todoExcel = new TodoExcel(vo.getTodo().getTitle(), vo.getUser().getName() + vo.getUser().getCode(), TodoTypeEnum.indexOf(vo.getTodo().getType()), TodoStatusEnum.indexOf(vo.getTodo().getStatus()), vo.getTodo().getDate(), vo.getTodo().getScore());
//            todoExcels.add(todoExcel);
//            String key = vo.getUser().getName() + vo.getUser().getCode();
//            if (vo.getTodo().getScore() == null) {
//                continue;
//            }
//            if (sum.containsKey(key)) {
//                BigDecimal tem = sum.get(key);
//                sum.put(key, tem.add(vo.getTodo().getScore()));
//            } else {
//                sum.put(key, vo.getTodo().getScore());
//            }
//        }
//        sum.keySet().forEach(key -> {
//            TodoSumExcel todoSumExcel = new TodoSumExcel(key, sum.get(key));
//            sumExcels.add(todoSumExcel);
//        });
//        //导出
//        response.setContentType("application/vnd.ms-excel");
//        response.setCharacterEncoding("utf-8");
//        response.setHeader("Content-disposition", "attachment;filename=down.xlsx");
//        try {
//            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
//            WriteSheet writeSheet1 = EasyExcel.writerSheet(0, "明细").head(TodoExcel.class).build();
//            excelWriter.write(todoExcels, writeSheet1);
//            WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "总数").head(TodoSumExcel.class).build();
//            excelWriter.write(sumExcels, writeSheet2);
//            excelWriter.finish();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }


    @Override
    public void downLoad(HttpServletResponse response, List<TodoVo> list) {
        try {
            List<TodoDown> datas = list.stream().map(item -> new TodoDown(item)).collect(Collectors.toList());
            response.setContentType("application/vnd.ms-excel" );
            response.setCharacterEncoding("utf-8" );
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试", "UTF-8" );
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx" );
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(0,"明细").head(TodoDown.class).build();
            excelWriter.write(datas,writeSheet);
            //统计
            writeSheet = EasyExcel.writerSheet(1,"统计").head(UserScore.class).build();
            excelWriter.write(sumScore(list), writeSheet);
            excelWriter.finish();
//            EasyExcel.write(response.getOutputStream(), TodoDown.class).sheet("模板" ).doWrite(datas);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public List<UserScore> sumScore(List<TodoVo> vos){
        Map<String,UserScore> sumMap = new HashMap<>();
        for (TodoVo vo:vos){
            if(vo.getUser()==null)continue;
            UserScore score = new UserScore(vo.getUser().getName(),vo.getUser().getCode(),BigDecimal.ZERO,BigDecimal.ZERO,vo.getUser().getProvince(),vo.getUser().getCity());
            if(sumMap.containsKey(vo.getUser().getCode())){
                score = sumMap.get(vo.getUser().getCode());
            }
            score.addScore(vo.getTodo().getScore(),vo.getTodo().getImgScore());
            sumMap.put(vo.getUser().getCode(),score);
        }
        return sumMap.values().stream().collect(Collectors.toList());
    }

    public static void main(String[] args) {
        // 写法1
        String fileName = "/Users/huangfei/Desktop/s1s.xlsx";
        // 这里 需要指定写用哪个class去写，然后写到第一个sheet，名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        ExcelWriter excelWriter = EasyExcel.write(fileName).build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(0, "明细").head(TodoExcel.class).build();
        TodoExcel todoExcel = new TodoExcel("2121", "", null, null, null, null);
        List<TodoExcel> todoExcels = new ArrayList<>();
        todoExcels.add(todoExcel);
        excelWriter.write(todoExcels, writeSheet1);
        excelWriter.finish();
    }

}
